﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GN.Pay.Application.GatewayApp.Dto.Input;
using GN.Pay.Application.GatewayApp.Dto.Output;
using GN.Pay.Core.Runtime.Caching;
using Abp.Dependency;
using GN.Pay.Core.Repositories;
using GN.Pay.Core.Services;
using GN.Pay.Core.Values.Channel;
using GN.Pay.Core.Exceptions;
using GN.Pay.Core.Entities;
using GN.Pay.Core.Runtime;
using Abp.AutoMapper;

namespace GN.Pay.Application.GatewayApp.Impl
{
    /// <summary>
    /// 银行卡应用服务
    /// </summary>
    public class BankCardAppService : GatewayAppService, IBankCardAppService
    {
        private readonly ICacheManager cacheManager;
        private readonly IIocManager iocManager;

        public BankCardAppService(ICacheManager cacheManager, IIocManager iocManager)
        {
            this.cacheManager = cacheManager;
            this.iocManager = iocManager;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public MerchantMemberBankCardBindApplyOutput MerchantMemberBankCardBindApply(BankCardBindApplyInput input)
        {
            var seriver = iocManager.Resolve<IProtocolPayService>();
            var memberRepository = iocManager.Resolve<IMerchantMemberRepository>();
            var member = memberRepository.FirstOrDefault(s => s.MerchantId == input.MerchantId && s.MemberNo == input.MemberNo);
            if (member == null)
            {
                var gen = iocManager.Resolve<IGenerateIdentifier>();
                member = new MerchantMember()
                {
                    Id = gen.GenerateMemberId(input.MerchantId, 1, 2),
                    IsCertification = false,
                    MemberName = "",
                    MemberNo = input.MemberNo,
                    MemberRealName = "",
                    MemberType = 1,
                    MerchantId = input.MerchantId
                };
                memberRepository.Insert(member);
            }
            var token = seriver.MerchantMemberBankCardBindApply(new MerchantMemberBankCardBindApplyInfo()
            {
                AccountName = input.AccountName,
                AccountNo = input.AccountNo,
                AccountType = input.AccountType,
                AppId = input.AppId,
                BankNo = input.BankNo,
                CreditCardLastNo = input.CreditCardLastNo,
                CreditCardLastTerm = input.CreditCardLastTerm,
                IdentityNo = input.IdentityNo,
                MobilePhone = input.MobilePhone,
                OpenBankCity = input.OpenBankCity,
                OpenBankName = input.OpenBankName,
                OpenBankProvince = input.OpenBankProvince,
                MemberId = member.Id
            });
            return new MerchantMemberBankCardBindApplyOutput() { Token = token };
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public MerchantMemberBankCardBindApplyOutput MerchantMemberBankCardBindApply(BankCardBindPayApplyInput input)
        {
            var ar1 = iocManager.Resolve<ITradePayApplyRepository>();
            var apply = ar1.Get(input.ApplyId);
            if (apply == null)
            {
                PayExceptionUtils.ThrowPayValidationException("支付申请已失效或支付已成功,无法再操作.");
            }
            if (string.IsNullOrWhiteSpace(apply.MemberNo))
            {
                PayExceptionUtils.ThrowPayValidationException("支付申请无会员信息,不支持绑定.");
            }
            var cacheService = iocManager.Resolve<ITradeCacheService>();
            var app = cacheService.GetMerchantAppInfo(apply.AppId);
            if (app == null)
            {
                PayExceptionUtils.ThrowPayValidationException("应用不存在或已下架。");
            }
            return MerchantMemberBankCardBindApply(new BankCardBindApplyInput()
            {
                BankNo = input.BankNo,
                AppId = apply.AppId,
                AccountName = input.AccountName,
                AccountType = input.AccountType,
                AccountNo = input.AccountNo,
                CreditCardLastNo = input.CreditCardLastNo,
                CreditCardLastTerm = input.CreditCardLastTerm,
                IdentityNo = input.IdentityNo,
                MemberNo = apply.MemberNo,
                MerchantId = app.MerchantId,
                MobilePhone = input.MobilePhone,
                OpenBankCity = input.OpenBankCity,
                OpenBankName = input.OpenBankName,
                OpenBankProvince = input.OpenBankProvince
            });
        }

        /// <summary>
        /// 银行卡绑定
        /// </summary>
        /// <param name="input">输入</param>
        /// <returns></returns>
        public BankCardOutput MerchantMemberBankCardBind(MerchantMemberBankCardBindInput input)
        {
            var info = input.MapTo<MerchantMemberBankCardBindInfo>();
            var seriver = iocManager.Resolve<IProtocolPayService>();
            var item = seriver.MerchantMemberBankCardBind(info);
            if (item == null)
            {
                return null;
            }
            var bankRepository = iocManager.Resolve<IBankInfoRepository>();
            var bank = bankRepository.Get(item.BankNo);
            if (bank == null)
            {
                PayExceptionUtils.ThrowPaySystemException("系统出错，绑定成功，但无法获取银行信息。");
            }
            return new BankCardOutput()
            {
                CardLastNo = item.AccountNo,
                Id = item.Id,
                State = item.State,
                CardType = item.AccountType,
                BankNo = item.BankNo,
                BankName = bank.BankName,
                BankLogoUrl = bank.LogoUrl
            };
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public List<BankCardOutput> MerchantMemberBankCardList(BankCardInput input)
        {
            var r1 = iocManager.Resolve<IMerchantMemberBankCardRepository>();
            var r2 = iocManager.Resolve<IMerchantMemberRepository>();
            var r3 = iocManager.Resolve<IBankInfoRepository>();
            var q = from p1 in r1.GetAll()
                    join p2 in r2.GetAll() on p1.MemberId equals p2.Id
                    join p3 in r3.GetAll() on p1.BankNo equals p3.Id
                    where p1.State > 0 && p2.MerchantId == input.MerchantId && p2.MemberNo == input.MemberNo
                    select new BankCardOutput()
                    {
                        Id = p1.Id,
                        BankLogoUrl = p3.LogoUrl,
                        BankName = p3.BankName,
                        BankNo = p1.BankNo,
                        CardLastNo = p1.AccountNo,
                        CardType = p1.AccountType,
                        State = p1.State,
                        MobilePhone = p1.MobilePhone
                    };
            return q.ToList();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="applyId"></param>
        /// <returns></returns>
        public List<BankCardOutput> MerchantMemberBankCardList(string applyId)
        {
            var ar1 = iocManager.Resolve<ITradePayApplyRepository>();
            var ar2 = iocManager.Resolve<IMerchantAppInfoRepository>();
            var r1 = iocManager.Resolve<IMerchantMemberBankCardRepository>();
            var r2 = iocManager.Resolve<IMerchantMemberRepository>();
            var r3 = iocManager.Resolve<IBankInfoRepository>();
            var q = from a1 in ar1.GetAll()
                    join a2 in ar2.GetAll() on a1.AppId equals a2.Id
                    join p2 in r2.GetAll() on a2.MerchantId equals p2.MerchantId
                    join p1 in r1.GetAll() on p2.Id equals p1.MemberId
                    join p3 in r3.GetAll() on p1.BankNo equals p3.Id
                    where p1.State > 0 && a1.Id == applyId && p2.MemberNo == a1.MemberNo
                    select new BankCardOutput()
                    {
                        Id = p1.Id,
                        BankLogoUrl = p3.LogoUrl,
                        BankName = p3.BankName,
                        BankNo = p1.BankNo,
                        CardLastNo = p1.AccountNo,
                        CardType = p1.AccountType,
                        State = p1.State,
                        MobilePhone = p1.MobilePhone,
                        ChannelId = p1.ChannelId
                    };
            return q.ToList();
        }


    }
}
